Skip to content

Run a pooler in front of every PostgresDatabase, and sign the program in as its own role - #113

Merged
qfeuilla merged 5 commits into
mainfrom
pg-connections
Oct 31, 2026
Merged

qfeuilla merged 5 commits into
mainfrom
pg-connections

Conversation

@qfeuilla

Copy link
Copy Markdown
Contributor

A PostgresDatabase no longer runs out of connections when the program scales. It now runs PgBouncer, in session mode, inside its own unit. A client that finds every connection busy waits for one instead of being refused, and one firing still keeps one real session.

What breaks for people who update

  • Clients outside the program sign in as app instead of weft. The password, host and port are the same, and weft infra env writes the new user.
  • A frontend's pool must expect the database to close a connection that sits idle for a minute.
  • An extension that needs the superuser goes in the node's new extensions setting.

What else changes

The database:

  • Existing databases are converted on their next start: the new role app is created and given ownership of everything the superuser owned.
  • Any existing database name keeps working. A name the pooler cannot read as written is reached through a door name made from it, which the connection carries.
  • A new database needs Postgres 14 or later. An existing older one keeps running without closing idle sessions, and warns of that on its card and in weft infra status through the new InfraSpec.notes.
  • The credential container passes the database name to psql through PGDATABASE, so a name containing = is read as a name.
  • It retries a refused setup every 30 seconds and shows why it is not ready on /health.
  • A reset whose password file cannot be written puts the role's exact old verifier back, so the pooler keeps working.

The Postgres nodes:

  • Connections a worker pools are closed after 5 seconds idle.
  • Watching queries use their own share of the pooler's connections and lift the idle limit for their own session.
  • A stopping worker gives back what its runs shared.

The rest of weft:

  • Cloud Run: after a settings change or an activation, the dispatcher reads the stored settings fresh, under the project's front lock, and removes that program's revisions under any other settings.
  • Infra setup, trigger setup and rebake failures now carry the reason the run failed with.
  • A failing health check's body now shows in weft infra status.
  • The fake node-test rig holds a publish to the access store's own check, against service recipes resolved over the whole catalog. The test hashes include those recipes.
  • The CLI test fake keeps a "closed" port bound for the life of the test process, so a parallel test cannot take it.

Tests run locally

  • Everything ci.yml and docs.yml run passes.
  • The four postgres e2e tests pass, including a new one: a watching query through the pooler keeps working past the one-minute idle limit.
  • A by-hand run on the real images: an old-style database named my-app is carried over with its rows.

… in as its own role

A PostgresDatabase now runs PgBouncer in session mode inside its unit, so
clients past the connections Postgres serves wait their turn instead of being
refused. Every client signs in as the role `app`, which owns the database and
is no superuser; existing databases are converted on their next start. Postgres
closes an `app` session idle for a minute, watching queries lift that limit
for their own session, and the worker pool closes connections idle for five
seconds.

Any existing database name keeps working: a name PgBouncer cannot read as
written gets a door name the connection carries. A new `extensions` setting
makes each listed extension as the superuser on every start. A new database
needs Postgres 14 or later; an existing older one keeps running, with a
warning through the new InfraSpec `notes` and on its card.

Also: a stopping worker lets go of what its runs shared; Cloud Run removes a
program's revisions under settings other than the stored ones after a
settings change or activation; infra and trigger setup failures, and a
rebake's, carry the reason; a failing health check's body is shown in
`weft infra status`; the fake node-test rig holds a publish to the access
store's check, against recipes resolved over the whole catalog; and the CLI
test fake keeps a closed port reserved so parallel tests cannot take it.
# Conflicts:
#	CHANGELOG.md
#	crates/weft-dispatcher/src/api/project.rs
@qfeuilla
qfeuilla merged commit d67f784 into main Oct 31, 2026
26 checks passed
@qfeuilla
qfeuilla deleted the pg-connections branch October 31, 2026 17:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants